#!/usr/bin/env python
"""
MD2PPT API 同步到 Apifox 脚本

这个脚本可以：
1. 启动 MD2PPT API 服务
2. 获取最新的 OpenAPI 规范
3. 生成格式化的 API 文档
4. 提供 Apifox 导入指导

使用方法：
    python scripts/sync_api_to_apifox.py
    python scripts/sync_api_to_apifox.py --port 8080
    python scripts/sync_api_to_apifox.py --output-dir ./api_docs
"""

import argparse
import asyncio
import json
import os
import sys
import subprocess
import time
import requests
from pathlib import Path
from datetime import datetime
import signal

class ApiSyncManager:
    def __init__(self, port=8001, output_dir="./api_docs"):
        self.port = port
        self.output_dir = Path(output_dir)
        self.base_url = f"http://localhost:{port}"
        self.openapi_url = f"{self.base_url}/openapi.json"
        self.process = None
        
        # 创建输出目录
        self.output_dir.mkdir(exist_ok=True)
        
    def start_api_server(self):
        """启动 API 服务器"""
        print(f"🚀 启动 MD2PPT API 服务器 (端口: {self.port})...")
        
        try:
            # 启动 API 服务器
            self.process = subprocess.Popen([
                sys.executable, "-m", "uvicorn", 
                "api.app:app", 
                f"--host=0.0.0.0", 
                f"--port={self.port}",
                "--reload=False"
            ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            
            # 等待服务器启动
            max_retries = 30
            for i in range(max_retries):
                try:
                    response = requests.get(f"{self.base_url}/health", timeout=2)
                    if response.status_code == 200:
                        print(f"✅ API 服务器已启动: {self.base_url}")
                        return True
                except requests.exceptions.RequestException:
                    if i < max_retries - 1:
                        print(f"⏳ 等待服务器启动... ({i+1}/{max_retries})")
                        time.sleep(1)
                    else:
                        print("❌ 服务器启动超时")
                        return False
                        
        except Exception as e:
            print(f"❌ 启动服务器失败: {e}")
            return False
            
    def stop_api_server(self):
        """停止 API 服务器"""
        if self.process:
            print("🛑 停止 API 服务器...")
            self.process.terminate()
            try:
                self.process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                self.process.kill()
                self.process.wait()
            self.process = None
            
    def fetch_openapi_spec(self):
        """获取 OpenAPI 规范"""
        print("📥 获取 OpenAPI 规范...")
        
        try:
            response = requests.get(self.openapi_url, timeout=10)
            response.raise_for_status()
            
            openapi_data = response.json()
            print(f"✅ 获取成功 (API版本: {openapi_data.get('info', {}).get('version', 'unknown')})")
            return openapi_data
            
        except requests.exceptions.RequestException as e:
            print(f"❌ 获取 OpenAPI 规范失败: {e}")
            return None
            
    def save_api_docs(self, openapi_data):
        """保存 API 文档"""
        if not openapi_data:
            return None
            
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        files = {}
        
        # 1. 保存原始 OpenAPI JSON
        openapi_file = self.output_dir / "md2ppt_api_openapi.json"
        with open(openapi_file, 'w', encoding='utf-8') as f:
            json.dump(openapi_data, f, ensure_ascii=False)
        files['openapi'] = openapi_file
        print(f"📄 已保存: {openapi_file}")
        
        # 2. 保存格式化版本
        formatted_file = self.output_dir / "md2ppt_api_formatted.json"
        with open(formatted_file, 'w', encoding='utf-8') as f:
            json.dump(openapi_data, f, ensure_ascii=False, indent=2)
        files['formatted'] = formatted_file
        print(f"📄 已保存: {formatted_file}")
        
        # 3. 保存带时间戳的备份
        backup_file = self.output_dir / f"md2ppt_api_backup_{timestamp}.json"
        with open(backup_file, 'w', encoding='utf-8') as f:
            json.dump(openapi_data, f, ensure_ascii=False, indent=2)
        files['backup'] = backup_file
        print(f"📄 已保存备份: {backup_file}")
        
        return files
        
    def generate_import_guide(self, openapi_data, files):
        """生成 Apifox 导入指南"""
        if not openapi_data:
            return None
            
        # 分析 API 信息
        api_info = openapi_data.get('info', {})
        paths = openapi_data.get('paths', {})
        
        # 统计接口数量
        endpoints_by_tag = {}
        total_endpoints = 0
        
        for path, methods in paths.items():
            for method, details in methods.items():
                if method.upper() in ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']:
                    total_endpoints += 1
                    tags = details.get('tags', ['未分类'])
                    for tag in tags:
                        if tag not in endpoints_by_tag:
                            endpoints_by_tag[tag] = []
                        endpoints_by_tag[tag].append({
                            'method': method.upper(),
                            'path': path,
                            'summary': details.get('summary', ''),
                            'description': details.get('description', '')
                        })
        
        # 生成导入指南
        guide_content = f"""# MD2PPT API 同步到 Apifox 指南

## 📊 API 概览

- **API 名称**: {api_info.get('title', 'MD2PPT API')}
- **版本**: {api_info.get('version', '1.0.0')}
- **描述**: {api_info.get('description', '')}
- **生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
- **接口总数**: {total_endpoints} 个

## 📁 生成的文件

"""
        
        for key, file_path in files.items():
            file_size = file_path.stat().st_size
            guide_content += f"- **`{file_path.name}`** ({file_size:,} bytes) - "
            if key == 'openapi':
                guide_content += "标准 OpenAPI 3.1 规范文件 (推荐导入此文件)\n"
            elif key == 'formatted':
                guide_content += "格式化版本，便于阅读和调试\n"
            elif key == 'backup':
                guide_content += f"带时间戳的备份文件\n"
                
        guide_content += f"""
## 🚀 Apifox 快速导入

### 方法一：文件导入（推荐）

1. **打开 Apifox**
   - 启动 Apifox 应用
   - 选择或创建项目

2. **导入 API 文档**
   ```
   导入 → OpenAPI/Swagger → 选择文件 → {files['openapi'].name}
   ```

3. **确认导入设置**
   - 导入方式：建议选择"覆盖"以获取最新接口
   - 项目名称：{api_info.get('title', 'MD2PPT API')}

### 方法二：URL 导入（需要服务运行）

如果 API 服务正在运行，可以直接使用 URL 导入：

```
URL: {self.base_url}/openapi.json
```

## 📋 接口分类详情

"""
        
        for tag, endpoints in endpoints_by_tag.items():
            guide_content += f"### {tag} ({len(endpoints)} 个接口)\n\n"
            for endpoint in endpoints:
                guide_content += f"- **{endpoint['method']}** `{endpoint['path']}` - {endpoint['summary']}\n"
            guide_content += "\n"
            
        guide_content += f"""## 🔧 环境配置建议

在 Apifox 中创建环境变量：

```json
{{
  "base_url": "{self.base_url}",
  "api_version": "v1"
}}
```

## 🧪 测试建议

1. **健康检查**: 先测试 `GET /health` 确认服务正常
2. **基础转换**: 测试 `POST /api/v1/convert` 基础功能
3. **文件上传**: 测试 `POST /api/v1/convert/upload` 文件处理
4. **批量操作**: 测试 `POST /api/v1/convert/batch` 批量转换

## 🔄 重新同步

当 API 有更新时，重新运行同步脚本：

```bash
python scripts/sync_api_to_apifox.py
```

## 📞 技术支持

- 📖 API 文档: {self.base_url}/docs
- 🔧 ReDoc: {self.base_url}/redoc
- 🔍 健康检查: {self.base_url}/health

---
*此文档由 MD2PPT API 同步脚本自动生成*
"""

        # 保存导入指南
        guide_file = self.output_dir / "apifox_import_guide.md"
        with open(guide_file, 'w', encoding='utf-8') as f:
            f.write(guide_content)
        print(f"📖 已生成导入指南: {guide_file}")
        
        return guide_file
        
    def generate_sync_script(self):
        """生成便捷同步脚本"""
        script_content = f"""#!/bin/bash
# MD2PPT API 快速同步脚本
# 自动生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

set -e

echo "🔄 开始同步 MD2PPT API 到 Apifox..."

# 切换到项目根目录
cd "$(dirname "$0")/.."

# 运行同步脚本
python scripts/sync_api_to_apifox.py

echo "✅ 同步完成！"
echo "📁 文件位置: {self.output_dir.absolute()}"
echo "📖 导入指南: {self.output_dir.absolute()}/apifox_import_guide.md"
"""

        script_file = Path("sync_to_apifox.sh")
        with open(script_file, 'w', encoding='utf-8') as f:
            f.write(script_content)
        
        # 添加执行权限
        os.chmod(script_file, 0o755)
        print(f"🔧 已生成快捷脚本: {script_file}")
        
        return script_file
        
    def run(self):
        """执行完整的同步流程"""
        print("🔄 开始 MD2PPT API 同步流程...")
        
        success = False
        try:
            # 1. 启动 API 服务器
            if not self.start_api_server():
                return False
                
            # 2. 获取 OpenAPI 规范
            openapi_data = self.fetch_openapi_spec()
            if not openapi_data:
                return False
                
            # 3. 保存 API 文档
            files = self.save_api_docs(openapi_data)
            if not files:
                return False
                
            # 4. 生成导入指南
            guide_file = self.generate_import_guide(openapi_data, files)
            
            # 5. 生成便捷脚本
            script_file = self.generate_sync_script()
            
            print(f"\n🎉 同步完成！")
            print(f"📁 输出目录: {self.output_dir.absolute()}")
            print(f"📄 主要文件: {files['openapi'].name}")
            print(f"📖 导入指南: {guide_file.name}")
            print(f"🔧 快捷脚本: {script_file}")
            
            print(f"\n🚀 下一步操作:")
            print(f"1. 打开 Apifox")
            print(f"2. 导入文件: {files['openapi'].absolute()}")
            print(f"3. 参考指南: {guide_file.absolute()}")
            
            success = True
            return True
            
        except KeyboardInterrupt:
            print("\n⚠️ 用户中断操作")
            return False
        except Exception as e:
            print(f"❌ 同步过程出错: {e}")
            return False
        finally:
            # 清理资源
            self.stop_api_server()
            if success:
                print("✅ 资源清理完成")

def main():
    parser = argparse.ArgumentParser(
        description="同步 MD2PPT API 到 Apifox",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
使用示例:
  python scripts/sync_api_to_apifox.py                    # 使用默认设置
  python scripts/sync_api_to_apifox.py --port 8080        # 指定端口
  python scripts/sync_api_to_apifox.py --output-dir docs  # 指定输出目录
        """
    )
    
    parser.add_argument(
        '--port', 
        type=int, 
        default=8001,
        help='API 服务器端口 (默认: 8001)'
    )
    
    parser.add_argument(
        '--output-dir',
        type=str,
        default='./api_docs',
        help='输出目录 (默认: ./api_docs)'
    )
    
    parser.add_argument(
        '--no-cleanup',
        action='store_true',
        help='不自动停止 API 服务器'
    )
    
    args = parser.parse_args()
    
    # 创建同步管理器
    sync_manager = ApiSyncManager(
        port=args.port,
        output_dir=args.output_dir
    )
    
    # 处理中断信号
    def signal_handler(sig, frame):
        print("\n⚠️ 接收到中断信号，正在清理...")
        sync_manager.stop_api_server()
        sys.exit(0)
        
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    # 执行同步
    success = sync_manager.run()
    
    sys.exit(0 if success else 1)

if __name__ == "__main__":
    main()